package com.yhk.wuchat.common.user.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yhk.wuchat.common.common.annotation.RedissonLock;
import com.yhk.wuchat.common.common.domain.vo.req.BlackReq;
import com.yhk.wuchat.common.common.event.UserBlackEvent;
import com.yhk.wuchat.common.common.event.UserRegisterEvent;
import com.yhk.wuchat.common.common.exception.BusinessException;
import com.yhk.wuchat.common.common.util.AssertUtil;
import com.yhk.wuchat.common.user.dao.BlackDao;
import com.yhk.wuchat.common.user.dao.ItemConfigDao;
import com.yhk.wuchat.common.user.dao.UserBackpackDao;
import com.yhk.wuchat.common.user.dao.UserDao;
import com.yhk.wuchat.common.user.domain.entity.*;
import com.yhk.wuchat.common.user.domain.enums.BlackTypeEnum;
import com.yhk.wuchat.common.user.domain.enums.ItemEnum;
import com.yhk.wuchat.common.user.domain.enums.ItemTypeEnum;
import com.yhk.wuchat.common.user.domain.vo.resp.BadgeResp;
import com.yhk.wuchat.common.user.domain.vo.resp.UserInfoResp;
import com.yhk.wuchat.common.user.service.UserService;
import com.yhk.wuchat.common.user.service.adapter.UserAdapter;
import com.yhk.wuchat.common.user.service.cache.ItemCache;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @version 1.0
 * @Author moresuo
 * @Date 2024/4/3 18:14
 * @注释
 */
@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserDao userDao;
    @Resource
    private UserBackpackDao userBackpackDao;

    @Resource
    private ItemCache itemCache;
    @Resource
    private ItemConfigDao itemConfigDao;
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;

    @Resource
    private BlackDao blackDao;

    /**
     * 用户注册
     * @param insert
     * @return
     */
    @Override
    @Transactional
    public Long register(User insert) {
        boolean save = userDao.save(insert);
        // 用户注册事件
        applicationEventPublisher.publishEvent(new UserRegisterEvent(this,insert));
        return null;
    }

    /**
     * 获取用户信息
     * @param uid
     * @return
     */
    @Override
    public UserInfoResp getUserInfo(Long uid) {
        User user = userDao.getById(uid);
        //剩余可改名次数
        Integer modifyNameCount = userBackpackDao.getCountByValidItemId(uid, ItemEnum.MODIFY_NAME_CARD.getId());
        return UserAdapter.buildUserInfo(user, modifyNameCount);
    }

    /**
     * 修改用户名
     * @param uid
     * @param name
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @RedissonLock(key = "#uid")
    public void modifyName(Long uid, String name) {
        User user=userDao.getByName(name);
        AssertUtil.isEmpty(user,"名字重复，请重新输入");
        UserBackpack modifyNameItem = userBackpackDao.getFirstValidItem(uid, ItemEnum.MODIFY_NAME_CARD.getId());
        AssertUtil.isNotEmpty(modifyNameItem,"改名卡不足");
        //使用改名卡，将状态设置为已使用
        boolean success = userBackpackDao.userItem(modifyNameItem);
        if(success){
            //改名
            userDao.modifyName(uid, name);
        }

    }

    /**
     * 可选徽章列表
     * @param uid
     * @return
     */
    @Override
    public List<BadgeResp> badges(Long uid) {
        List<ItemConfig> itemConfigs = itemCache.getByType(ItemTypeEnum.BADGE.getType());
        //查询用户拥有的徽章
        List<Long> ids = itemConfigs.stream().map(ItemConfig::getId).collect(Collectors.toList());
        List<UserBackpack> backpacks = userBackpackDao.getByItemIds(uid, ids);
        //查询用户佩戴的徽章
        User user = userDao.getById(uid);
        return UserAdapter.buildBadgeResp(itemConfigs, backpacks, user);
    }

    /**
     * 穿戴徽章
     * @param uid
     * @param itemId
     */
    @Override
    public void wearingBadge(Long uid, Long itemId) {
        //确保有徽章
        UserBackpack firstValidItem = userBackpackDao.getFirstValidItem(uid, itemId);
        AssertUtil.isNotEmpty(firstValidItem, "你没有该徽章");
        ItemConfig itemConfig = itemConfigDao.getById(firstValidItem.getItemId());
        AssertUtil.equal(itemConfig.getType(), ItemTypeEnum.BADGE.getType(), "该物品不是徽章");
        //佩戴
        userDao.wearingBadge(uid, itemId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void black(BlackReq blackReq) {
        Long uid=blackReq.getUid();
        Black black=new Black();
        black.setType(BlackTypeEnum.UID.getType());
        black.setTarget(uid.toString());
        blackDao.save(black);
        User user = userDao.getById(uid);
        blackIp(Optional.ofNullable(user.getIpInfo()).map(IpInfo::getCreateIp).orElse(null));
        blackIp(Optional.ofNullable(user.getIpInfo()).map(IpInfo::getUpdateIp).orElse(null));
        applicationEventPublisher.publishEvent(new UserBlackEvent(this,user));
    }

    private void blackIp(String ip) {
        if(StrUtil.isBlank(ip)){
            return;
        }
        try{
            Black black=new Black();
            black.setType(BlackTypeEnum.IP.getType());
            black.setTarget(ip);
            blackDao.save(black);
        }catch (Exception e){
            throw new BusinessException("黑名单ip失败");
        }

    }


}
